#include "stdafx.h"
#include "ui_freetype_font_manager.h"

#include "ui_sysfont_map.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include <ftglyph.h>
#include <ftsynth.h>

#ifdef FORCELIB
#pragma comment(lib, "freetype_MT")
#else
#ifdef _DEBUG
#pragma comment(lib, "freetype_D")
#else
#pragma comment(lib, "freetype")
#endif
#endif


_SSL_BEGIN
_SSUIL_BEGIN
//
//
//
UIFtFontIdInfo::UIFtFontIdInfo()
{
	// font_face_name
	bold = 0;
	italic = 0;
	underline = 0;
	size = 12;
}

UIFtCharInfo::UIFtCharInfo()
{
	// font_id_info
	ch = 0;
}

bool UIFtCharInfo::operator <(const UIFtCharInfo& other) const
{
	if(font_id_info.font_face_name != other.font_id_info.font_face_name)
		return font_id_info.font_face_name < other.font_id_info.font_face_name;

	if(ch != other.ch)
		return ch < other.ch;

	if(font_id_info.size != other.font_id_info.size)
		return font_id_info.size < other.font_id_info.size;

	if(font_id_info.bold != other.font_id_info.bold)
		return font_id_info.bold < other.font_id_info.bold;

	if(font_id_info.italic != other.font_id_info.italic)
		return font_id_info.italic < other.font_id_info.italic;

	if(font_id_info.underline != other.font_id_info.underline)
		return font_id_info.underline < other.font_id_info.underline;

	return false;
}

//
//
//
UIFreetypeFontManager::UIFreetypeFontManager()
{
	library_ = NULL;
	FT_Library lib;
	FT_Init_FreeType(&lib);
	library_ = lib;
}

UIFreetypeFontManager::~UIFreetypeFontManager()
{
	for(UIFtCharInfos::iterator iter=char_infos_.begin(); iter!=char_infos_.end(); iter++)
	{
		if(iter->second == NULL)
			continue;
		delete iter->second;
		iter->second = NULL;
	}
	char_infos_.clear();

	for(UIFtFontLibs::iterator iter=font_infos_.begin(); iter!=font_infos_.end(); iter++)
	{
		RemoveFontLib(iter->second);
	}
	font_infos_.clear();

	if(library_ != NULL)
	{
		FT_Done_FreeType((FT_Library)library_);
		library_ = NULL;
	}
}

bool UIFreetypeFontManager::AddFontLib(const tchar * font_file, const tstring &font_face_name)
{
	if(font_face_name.empty() || font_file == NULL)
		return false;
	DWORD attris = ::GetFileAttributes(font_file);
	if(attris == INVALID_FILE_ATTRIBUTES ||
		(attris & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
		return false;
	UIFtFontLibs::iterator iter = font_infos_.find(font_face_name);
	if(iter != font_infos_.end())
	{
		RemoveFontLib(iter->second);
		font_infos_.erase(iter);
	}
	UIFtFontLib font_info;
	font_info.font_face_name = font_face_name;
	font_info.font_file = font_file;
	font_info.font_face = NULL;
	font_infos_[font_face_name] = font_info;
	return true;
}

bool UIFreetypeFontManager::AddMemoryFontLib(const unsigned char *buffer, size_t len, const tstring &font_face_name)
{
	if(font_face_name.empty() || buffer == NULL || len == 0)
		return false;

	if(library_ == NULL)
		return false;

	UIFtFontLibs::iterator iter = font_infos_.find(font_face_name);
	if(iter != font_infos_.end())
	{
		RemoveFontLib(iter->second);
		font_infos_.erase(iter);
	}

	UIFtFontLib font_info;

	FT_Face font_face = NULL;
	font_info.font_buffer = (unsigned char *)malloc(len);
	memcpy(font_info.font_buffer, buffer, len);
	FT_Error ret = FT_New_Memory_Face((FT_Library)library_, font_info.font_buffer, len, 0, &font_face);
	if(ret != 0)
		goto error;

	ret = FT_Select_Charmap(font_face, FT_ENCODING_UNICODE);
	if(ret != 0)
		goto error;

	font_info.font_face = font_face;
	font_info.font_face_name = font_face_name;
	font_info.font_file.clear();
	font_infos_[font_face_name] = font_info;
	return true;
error:
	if(font_info.font_buffer != NULL)
	{
		free(font_info.font_buffer);
		font_info.font_buffer = NULL;
	}
	if(font_face != NULL)
	{
		FT_Done_Face(font_face);
	}
	return false;
}

void UIFreetypeFontManager::RemoveFontLib(UIFtFontLib &font_info)
{
	if(font_info.font_face != NULL)
	{
		FT_Done_Face((FT_Face)font_info.font_face);
		font_info.font_face = NULL;
	}
	if(font_info.font_buffer != NULL)
	{
		free(font_info.font_buffer);
		font_info.font_buffer = NULL;
	}
}

void UIFreetypeFontManager::AddFontId(const tstring &font_id, const UIFtFontIdInfo &id_info)
{
	font_id_infos_[font_id] = id_info;
}

bool UIFreetypeFontManager::GetFontInfo(const tstring &font_id, ss_out_ UIFtFontIdInfo &id_info)
{
	UIFtFontIdInfos::iterator iter = font_id_infos_.find(font_id);
	if(iter == font_id_infos_.end())
	{
		iter = font_id_infos_.find(default_font_id_.c_str());
	}
	if(iter == font_id_infos_.end())
		return false;
	id_info = iter->second;
	return true;
}

void UIFreetypeFontManager::SetDefaultFont(const tstring &font_id)
{
	default_font_id_ = font_id;
}

//////////////////////////////////////////////////////////////////////////
UIFtCharImgInfo* UIFreetypeFontManager::GetCharImage(const UIFtCharInfo &ch)
{
	UIFtCharInfos::iterator iter = char_infos_.find(ch);
	if(iter != char_infos_.end())
		return iter->second;

	FT_Face face = (FT_Face)GetFontFace(ch.font_id_info.font_face_name);
	if(face == NULL)
		return NULL;

	if(ch.font_id_info.italic)
	{
		FT_Matrix matrix;
		matrix.xx = 1 << 16;
		matrix.xy = 0x5800;
		matrix.yx = 0;
		matrix.yy = 1 << 16;
		FT_Set_Transform(face, &matrix, 0);
	}else
	{
		FT_Set_Transform(face, NULL, 0);
	}
	FT_Set_Pixel_Sizes(face, ch.font_id_info.size, 0);

	FT_UInt idx = FT_Get_Char_Index( face, ch.ch);
	if(idx == 0)
		return NULL;
	//FT_Load_Glyph(face, idx, FT_LOAD_DEFAULT);
	FT_Load_Glyph(face, idx, FT_LOAD_NO_AUTOHINT | FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO);

	FT_Glyph glyph;
	FT_Get_Glyph(face->glyph, &glyph);

	if(ch.font_id_info.bold)
	{
		FT_GlyphSlot_Embolden(face->glyph);
	}
	FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
	//FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);


	FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1);
	FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
	FT_Bitmap& bitmap=bitmap_glyph->bitmap;

	UIFtCharImgInfo *font_img_info = new UIFtCharImgInfo;
	font_img_info->img_width = bitmap.width;
	font_img_info->img_height = bitmap.rows;
	font_img_info->draw_offset_left = face->glyph->bitmap_left;
	if(font_img_info->draw_offset_left < 0)
		font_img_info->draw_offset_left = 0;
	font_img_info->draw_offset_top = (face->size->metrics.ascender >> 6) - face->glyph->bitmap_top;
	//font_img_info->draw_offset_top+=1;
	if(font_img_info->draw_offset_top < 0)
		font_img_info->draw_offset_top = 0;
	font_img_info->slot_width = face->glyph->advance.x / 64;
	font_img_info->slot_height = ch.font_id_info.size + 4;
	if(font_img_info->img_width > font_img_info->slot_width)
		font_img_info->slot_width = font_img_info->img_width;
	if(font_img_info->draw_offset_top + font_img_info->img_height > font_img_info->slot_height)
		font_img_info->draw_offset_top = font_img_info->slot_height -  font_img_info->img_height;
	if(font_img_info->draw_offset_top < 0)
	{
		font_img_info->slot_height -= font_img_info->draw_offset_top;
		font_img_info->draw_offset_top = 0;
	}
	unsigned char *buffer = font_img_info->img_buffer.alloc_ptr(
		font_img_info->slot_width * font_img_info->slot_height);
	memset(buffer, 0, font_img_info->slot_width * font_img_info->slot_height);

	switch(bitmap.pixel_mode)
	{
	case FT_PIXEL_MODE_GRAY:
		{
			for(int i=0; i<font_img_info->img_height; i++)
			{

				memcpy(&buffer[(i+font_img_info->draw_offset_top) * font_img_info->slot_width
					+ font_img_info->draw_offset_left],
					&bitmap.buffer[i*font_img_info->img_width],
					font_img_info->img_width);
			}
		}
		break;
	case FT_PIXEL_MODE_MONO:
		{
			for(int i=0; i<font_img_info->img_height; i++)
			{
				for(int j=0; j<font_img_info->img_width; j++)
				{
					buffer[(i+font_img_info->draw_offset_top) * font_img_info->slot_width + j] =
#if 1
						bitmap.buffer[i * bitmap.pitch + j / 8] & (0x80 >> (j & 7)) ? 255 : 0;
#else
						(bitmap.buffer[i * bitmap.pitch + (j/8)]<<(j%8))&0x80;
#endif
				}
			}
		}
		break;
	}

	if(ch.font_id_info.underline)
	{
		memset(buffer + (font_img_info->slot_height-1) * font_img_info->slot_width,
			0xff, font_img_info->slot_width);
	}

	FT_Done_Glyph(glyph);
	char_infos_[ch] = font_img_info;
	return font_img_info;
}

#include "sscvt/cvt_cls.h"
void* UIFreetypeFontManager::GetFontFace(const tstring &font_face_name)
{
	if(library_ == NULL)
		return NULL;
	UIFtFontLibs::iterator iter = font_infos_.find(font_face_name);
	if(iter == font_infos_.end())
	{
		tstring font_file = stl_singleton<UISysFontMap>::GetInstance()->FontPathFromName(font_face_name);
		if(font_file.empty())
			return NULL;
		AddFontLib(font_file.c_str(), font_face_name);
	}
	iter = font_infos_.find(font_face_name);
	if(iter == font_infos_.end())
		return NULL;
	if(iter->second.font_face != NULL)
		return iter->second.font_face;
	FT_Face font_face = NULL;

	FT_Error ret = FT_New_Face((FT_Library)library_,
		auto_cvt(iter->second.font_file.c_str()).c_utf8str(), 0, &font_face); // TBD
	if(ret != 0)
		return NULL;

	ret = FT_Select_Charmap(font_face, FT_ENCODING_UNICODE);
	if(ret != 0)
		goto error;

	iter->second.font_face = font_face;
	return iter->second.font_face;

error:
	FT_Done_Face(font_face);
	return NULL;
}

_SSUIL_END
_SSL_END
